#server.py

import time
import json
from flask import Flask, jsonify, request, send_from_directory, Response
from flask_cors import CORS
import time
from werkzeug.utils import secure_filename # 用于安全地处理文件名
import queue

# --- 配置 ---
# 设置包含你所有前端文件 (html, css, js, pages) 的目录
FRONTEND_FOLDER = '../'

# 创建 Flask 应用
app = Flask(__name__)

# 为所有路由启用CORS，这允许从其他源（例如 VS Code Live Server）进行API调用
CORS(app)

# --- 模拟数据 ---
fake_device_info = {
    "version": "1.0.0-dev",
    "chip_id": "SIMULATED_CHIP_12345",
    "wifi_mode": "STA",
    "ip_address": "172.23.82.238",
    "uptime": 0,
    "cpu_temp": 42.5,
    "free_heap": 150 * 1024 # 150 KB
}
start_time = time.time()

# --- 模拟设备的实时状态 ---
fake_device_realtime_status = {
    "uptime_s": int(time.time() - start_time),
    "device_time": "", # JS 会格式化
    "relay_state": True, # True for ON, False for OFF
    "temperature": 25.3,
    "humidity": 53.2,
    "current": 0.1, # Amps
    "voltage": 220.5, # Volts
    "power": 22.05, # Watts
    "energy": 1.23, # kWh
    "rs485_baudrate": 9600
}

# --- 用于SSE的全局广播队列 ---
# 这是一个线程安全的队列，用于在不同的请求处理函数之间传递消息
# 但在Flask的单线程开发服务器中，我们主要用它来解耦
sse_broadcaster = queue.Queue()

# --- API Endpoints (模拟ESP32的API) ---

# --- 新增：SSE Endpoint ---
@app.route('/api/sse')
def sse_endpoint():
    """建立SSE连接并推送实时数据"""
    
    def event_stream():
        print("SSE client connected.")
        # 发送一条初始连接成功的消息 (可选)
        yield f"event: connected\ndata: {json.dumps({'message': 'Connection established'})}\n\n"
        
        last_sent_data = {} # 存储上次发送的数据，只在变化时发送

        while True:
            # 模拟从设备获取最新状态
            current_time = time.time()
            fake_device_realtime_status["uptime_s"] = int(current_time - start_time)
            fake_device_realtime_status["device_time"] = int(current_time)
            fake_device_realtime_status["temperature"] = round(25.0 + (current_time % 3) - 1.5, 1)
            fake_device_realtime_status["humidity"] = round(55.0 - (current_time % 5), 1)

            # 只有当数据发生变化时才推送
            # 在真实设备上，你会根据传感器读数或状态变化来触发
            if fake_device_realtime_status != last_sent_data:
                # 格式化为 SSE data 字段
                data_str = json.dumps(fake_device_realtime_status)
                sse_message = f"data: {data_str}\n\n"
                
                # print(f"SSE sending data: {data_str}")
                yield sse_message # 发送数据给客户端
                
                last_sent_data = fake_device_realtime_status.copy()

            time.sleep(1) # 每秒检查一次状态变化

    # 返回一个流式响应，MIME类型为 text/event-stream
    return Response(event_stream(), mimetype='text/event-stream')

@app.route('/api/ir/send', methods=['POST'])
def ir_send():
    """模拟发送红外命令"""
    data = request.json
    print(f"API-HINT: IR command to send: {data}")
    return jsonify({"message": f"命令已发送: {data.get('command')} -> {data.get('value')}"})

@app.route('/api/ir/learn', methods=['POST'])
def ir_learn_new():
    """模拟学习红外命令"""
    data = request.json
    print(f"API-HINT: Learning IR command for: {data}")
    # 模拟学习过程需要时间
    time.sleep(3) 
    print(f"API-HINT: Learning successful for {data.get('command')}")
    return jsonify({"message": f"成功学习: {data.get('command')} -> {data.get('value')}"})

@app.route('/api/status/realtime')
def get_realtime_status():
    """返回设备的实时状态数据"""
    # 模拟数据变化
    current_time = time.time()
    fake_device_realtime_status["uptime_s"] = int(current_time - start_time)
    fake_device_realtime_status["device_time"] = int(current_time) # 返回Unix时间戳
    fake_device_realtime_status["temperature"] = 25.0 + (current_time % 3) - 1.5
    fake_device_realtime_status["humidity"] = 55.0 - (current_time % 5)
    
    print("API-HINT: /api/status/realtime called")
    return jsonify(fake_device_realtime_status)

@app.route('/api/control/relay', methods=['POST'])
def control_relay():
    """控制继电器"""
    data = request.json
    state = data.get('state') # 期望收到 { "state": true } or { "state": false }
    fake_device_realtime_status['relay_state'] = state
    status_text = "ON" if state else "OFF"
    print(f"API-HINT: Relay set to {status_text}")
    return jsonify({"message": f"Relay turned {status_text}", "relay_state": state})

@app.route('/api/control/sync-time', methods=['POST'])
def sync_time():
    """模拟时间同步"""
    print("API-HINT: Time sync command received.")
    time.sleep(1) # 模拟同步耗时
    return jsonify({"message": "Time synchronized successfully!"})

@app.route('/api/config/rs485', methods=['POST'])
def set_rs485_config():
    """保存RS485配置"""
    data = request.json
    baudrate = data.get('baudrate')
    fake_device_realtime_status['rs485_baudrate'] = int(baudrate)
    print(f"API-HINT: RS485 baudrate set to {baudrate}")
    return jsonify({"message": f"RS485 baudrate set to {baudrate}"})

@app.route('/api/control/ir-learn', methods=['POST'])
def ir_learn():
    """模拟红外学习"""
    print("API-HINT: IR learning started...")
    time.sleep(3) # 模拟学习过程
    print("IR signal captured!")
    return jsonify({"message": "Successfully learned IR signal!", "code": "NEC:0x12345678"})

@app.route('/api/login', methods=['POST'])
def login():
    """处理登录请求"""
    data = request.json
    username = data.get('username')
    password = data.get('password')
    
    print(f"API-HINT: Login attempt for user '{username}'")
    
    # 模拟验证逻辑
    # 在真实设备上，你会从配置中读取并验证用户名和密码
    if username == "admin" and password == "admin":
        print("Login successful.")
        return jsonify({"message": "Login successful"}), 200
    else:
        print("Login failed.")
        return jsonify({"message": "Invalid username or password"}), 401 # 401 Unauthorized

@app.route('/api/account/change-password', methods=['POST'])
def change_password():
    """模拟修改密码"""
    data = request.json
    print(f"API-HINT: /api/account/change-password called with data: {data}")
    
    current_pw = data.get('current_password')
    new_pw = data.get('new_password')
    confirm_pw = data.get('confirm_password')

    if not all([current_pw, new_pw, confirm_pw]):
        return jsonify({"message": "All fields are required."}), 400
    
    if current_pw != "admin": # 模拟当前密码是 'admin'
        return jsonify({"message": "Incorrect current password."}), 403 # 403 Forbidden
        
    if new_pw != confirm_pw:
        return jsonify({"message": "New passwords do not match."}), 400
        
    print(f"Simulating password change to '{new_pw}'...")
    return jsonify({"message": "Password updated successfully!"})

@app.route('/api/ota/upload', methods=['POST'])
def ota_upload():
    """模拟固件上传"""
    if 'firmware' not in request.files:
        return 'No firmware file part', 400
    file = request.files['firmware']
    if file.filename == '':
        return 'No selected file', 400
    
    if file and file.filename.endswith('.bin'):
        filename = secure_filename(file.filename)
        print(f"API-HINT: Received firmware file: {filename}")
        # 在实际设备上，这里会保存文件并启动OTA进程
        # 模拟处理时间
        time.sleep(2) # 模拟后台处理
        print("Firmware processing complete.")
        return 'Upload successful, device is updating.', 200
    
    return 'Invalid file type, only .bin is allowed', 400

@app.route('/api/factory-reset', methods=['POST'])
def factory_reset():
    """模拟恢复出厂设置"""
    print("\n" + "="*40)
    print("API-HINT: FACTORY RESET INITIATED!")
    print("All settings would be cleared on a real device.")
    print("="*40 + "\n")
    time.sleep(3) # 模拟操作耗时
    return jsonify({"message": "Factory reset successful. Device is rebooting."})

# --- API Endpoints for Service Configuration ---
@app.route('/api/config/tcp-server', methods=['POST'])
def set_tcp_server_config():
    """保存TCP Server配置"""
    data = request.json
    print(f"API-HINT: /api/config/tcp-server called with data: {data}")
    
    # 可以在这里添加验证逻辑
    if data.get('enabled') and 'port' not in data:
        return jsonify({"message": "Port is required when TCP Server is enabled."}), 400
        
    return jsonify({"message": "TCP Server settings saved successfully!"})

@app.route('/api/config/tcp-client', methods=['POST'])
def set_tcp_client_config():
    """保存TCP Client配置"""
    data = request.json
    print(f"API-HINT: /api/config/tcp-client called with data: {data}")
    
    if data.get('enabled') and ('host' not in data or 'port' not in data):
        return jsonify({"message": "Host and Port are required when TCP Client is enabled."}), 400
        
    return jsonify({"message": "TCP Client settings saved successfully!"})

@app.route('/api/config/udp-server', methods=['POST'])
def set_udp_server_config():
    """保存UDP Server配置"""
    data = request.json
    print(f"API-HINT: /api/config/udp-server called with data: {data}")
    
    if data.get('enabled') and 'port' not in data:
        return jsonify({"message": "Port is required when UDP Server is enabled."}), 400
        
    return jsonify({"message": "UDP Server settings saved successfully!"})

@app.route('/api/config/udp-client', methods=['POST'])
def set_udp_client_config():
    """保存UDP Client配置"""
    data = request.json
    print(f"API-HINT: /api/config/udp-client called with data: {data}")

    if data.get('enabled') and ('host' not in data or 'port' not in data):
        return jsonify({"message": "Host and Port are required when UDP Client is enabled."}), 400
        
    return jsonify({"message": "UDP Client settings saved successfully!"})

@app.route('/api/config/ethernet', methods=['POST'])
def set_ethernet_config():
    """保存以太网配置"""
    data = request.json
    print(f"API-HINT: /api/config/ethernet called with data: {data}")
    # 在这里，你可以添加一些验证逻辑
    if not data or 'eth_mode' not in data:
        return jsonify({"message": "Invalid data received for Ethernet."}), 400
    
    print(f"Simulating save for Ethernet config...")
    # 成功响应
    return jsonify({"message": "Ethernet settings saved successfully!"})

@app.route('/api/config/wifi', methods=['POST'])
def set_wifi_config():
    """保存Wi-Fi配置"""
    data = request.json
    print(f"API-HINT: /api/config/wifi called with data: {data}")
    # 在这里，你可以添加一些验证逻辑
    if not data or 'ssid' not in data or 'wifi_mode' not in data:
        return jsonify({"message": "Invalid data received for Wi-Fi."}), 400
    
    print(f"Simulating save for Wi-Fi config (SSID: {data.get('ssid')})...")
    # 成功响应
    return jsonify({"message": "Wi-Fi settings saved successfully!"})

@app.route('/api/version')
def get_version():
    """返回固件版本"""
    print("API-HINT: /api/version called")
    return jsonify({"version": fake_device_info["version"]})

@app.route('/api/status')
def get_status():
    """返回完整的设备状态，用于状态页面的实时更新"""
    print("API-HINT: /api/status called")
    # 模拟运行时间
    fake_device_info["uptime"] = int(time.time() - start_time)
    # 模拟温度和内存变化
    fake_device_info["cpu_temp"] = 42.5 + (time.time() % 5) - 2.5
    fake_device_info["free_heap"] = (150 + (time.time() % 10) * 2) * 1024

    fake_device_info["hostname"] = "网关"
    
    return jsonify(fake_device_info)

@app.route('/api/config/network', methods=['POST'])
def set_network_config():
    """保存网络配置"""
    data = request.json
    print(f"API-HINT: /api/config/network called with data: {data}")
    # 在这里，你可以添加一些验证逻辑
    if not data or 'ssid' not in data:
        return jsonify({"message": "Invalid data received."}), 400
    
    print(f"Simulating save for SSID: {data.get('ssid')}")
    # 成功响应
    return jsonify({"message": "Settings saved successfully on dev server!"})

@app.route('/api/reboot', methods=['POST'])
def reboot_device():
    """模拟重启设备"""
    print("\n" + "="*30)
    print("API-HINT: /api/reboot called. SIMULATING RESTART...")
    print("="*30 + "\n")
    return jsonify({"message": "Reboot command received."})

# --- 文件服务 (用于提供HTML, CSS, JS文件) ---

# 根路径，提供 index.html
@app.route('/')
def serve_index():
    return send_from_directory(FRONTEND_FOLDER, 'index.html')

# 提供其他所有前端文件 (css, js, images, pages)
@app.route('/<path:path>')
def serve_static_files(path):
    return send_from_directory(FRONTEND_FOLDER, path)


# --- 启动服务器 ---
if __name__ == '__main__':
    # host='0.0.0.0' 使服务器可以从网络中的任何设备访问
    # debug=True 启用调试模式，修改代码后服务器会自动重启
    app.run(host='0.0.0.0', port=5555, debug=True)